home *** CD-ROM | disk | FTP | other *** search
- ///////////////////////////////////////////////////////
- // Listing 2 - QC.CPP: Quadcode support routines
- // Written by:
- // Kenneth Van Camp
- // RR #1 Box 1255
- // East Stroudsburg, PA 18301
- // (717)223-8620
- //
- // Functions -
- // QuadCode::FreeMem free memory from qc
- // QuadCode::QuadCode constructor from (I,J)
- // QuadCode::Init initializer from string
- // QuadCode::GetQuit get val of single quit
- // QuadCode::SetQuit set val of single quit
- // QuadCode::ToIJ convert to (I,J) coords
- // QuadCode::Compare compare two quadcodes
- // QuadCode::Sibling are two qc's siblings?
- // QuadCode::Contains does qc contain it?
- // QuadCode::MakeParent make qc into its parent
- // QuadCode::operator= assignment operator
- // operator<< qc "put to" stream
- // operator>> qc "get from" stream
- //
- ///////////////////////////////////////////////////////
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #ifdef __TURBOC__
- #include <iostream.h>
- #else
- #include <stream.hpp>
- #endif
- #include "qc.h"
-
- // The following macro returns the number of bytes reqd
- // to store a quadcode, given the number of quits:
- #define QC_NBYTES(q) (((q) - 1) / 4 + 1)
-
- // These are shifts & masks to extract a single quit
- static int QCshifts[4] = { 6, 4, 2, 0 };
- static int QCmasks[4] = { 3<<6, 3<<4, 3<<2, 3 };
- // This is the inverse mask:
- static int QCimasks[4] =
- { 0xff^(3<<6), 0xff^(3<<4), 0xff^(3<<2), 0xff^3 };
- // And these are masks for each bit in a normal byte:
- static int bitmasks[8] =
- { 1, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7 };
-
- ///////////////////////////////////////////////////////
- // QuadCode::FreeMem: Free dynamic memory.
-
- #ifndef STAT_QC
- void QuadCode::FreeMem (void)
- {
- if (nquits > 0 && qca)
- delete qca;
- qca = NULL;
- nquits = 0;
- } // QuadCode::FreeMem
- #endif // STAT_QC
-
- ///////////////////////////////////////////////////////
- // QuadCode::QuadCode: QuadCode constructor from (I,J)
- // coordinates of the upper-left corner of the qc.
-
- QuadCode::QuadCode (COORD i, COORD j, int nq)
- // i is the vertical row# of quadcode (0 at top)
- // j is the horizontal column# of quadcode
- // nq is the # of quits in quadcode
- {
- #ifndef STAT_QC
- qca = NULL;
- #endif
- nquits = 0;
- assert (nq > 0 && nq <= MAXQUITS);
-
- // We traverse both the (i,j) coordinates and the qc
- // from the msb to the lsb and msq to msq. Note the
- // following assumes MAXQUITS is a multiple of 8.
- #ifdef MSB_FIRST
- BYTE *ip = (BYTE *)&i + (MAXQUITS - nq) / 8;
- BYTE *jp = (BYTE *)&j + (MAXQUITS - nq) / 8;
- #else
- BYTE *ip = (BYTE *)&i + sizeof(COORD) - 1 -
- (MAXQUITS - nq) / 8;
- BYTE *jp = (BYTE *)&j + sizeof(COORD) - 1 -
- (MAXQUITS - nq) / 8;
- #endif
-
- int bit = 7 - (MAXQUITS - nq) % 8;
- int nbytes = QC_NBYTES (nq);
- #ifndef STAT_QC
- qca = new BYTE [nbytes];
- assert (qca != NULL);
- #endif
-
- memset (qca, '\0', nbytes);
- BYTE *p = qca;
- nquits = nq;
-
- int pos = 0; // position within qc (0,1,2,3)
- for ( ; nq > 0; nq--)
- {
- if (*ip & bitmasks[bit])
- *p |= 1 << (QCshifts[pos] + 1);
- if (*jp & bitmasks[bit])
- *p |= 1 << QCshifts[pos];
- // Advance to next quit
- if (++pos > 3)
- {
- pos = 0;
- p++;
- }
- // Back up to next bit
- if (--bit < 0)
- {
- bit = 7;
- #ifdef MSB_FIRST
- ip++;
- jp++;
- #else
- ip--;
- jp--;
- #endif
- } // if --bit
-
- } // for nq
-
- } // QuadCode::QuadCode
-
- ///////////////////////////////////////////////////////
- // QuadCode::Init: QuadCode initializer from string.
-
- void QuadCode::Init (const char *chqc)
- // chqc is the quadcode in a null-terminated
- // character representation - i.e., "123"
- {
- int nq = strlen (chqc);
- #ifndef STAT_QC
- qca = NULL;
- #endif
- nquits = 0;
- assert (nq > 0 && nq <= MAXQUITS);
- size_t nbytes = QC_NBYTES (nq);
- #ifndef STAT_QC
- qca = new BYTE [nbytes];
- assert (qca != NULL);
- #endif
- memset (qca, '\0', nbytes);
-
- // Store quadcode in binary form, from msq to lsq.
- int i;
- int pos; // pos within byte of this quit (0,1,2,3)
- BYTE *p; // ptr to current byte in qc
- for (i = 0, pos = 0, p = qca; i < nq; i++)
- {
- int val = chqc[i] - '0';
- assert (val >= 0 && val <= 3);
- *p |= val << QCshifts[pos];
- if (++pos > 3)
- {
- pos = 0;
- p++;
- }
- } // for i
-
- nquits = nq;
- } // QuadCode::Init
-
- ///////////////////////////////////////////////////////
- // QuadCode::GetQuit: Return single quit from quadcode.
-
- int QuadCode::GetQuit (int quit)
- // quit is the pos# of the quit to extract (zero-based).
- // Pos 0 is the high-order quit ('1' in "123").
- {
- assert (quit <= nquits && quit >= 0);
-
- int byte = quit / 4;
- int pos = quit % 4;
- return ( (*(qca + byte) & QCmasks[pos]) >>
- QCshifts[pos]);
- } // QuadCode::GetQuit
-
- ///////////////////////////////////////////////////////
- // QuadCode::SetQuit: Set value of a single quit.
-
- void QuadCode::SetQuit (int quit, int val)
- // quit is the pos# of the quit to extract (zero-based).
- // val is the value of the quit (0, 1, 2 or 3).
- {
- assert (quit <= nquits && quit >= 0 && val >= 0 &&
- val < 4);
-
- BYTE *p = qca + quit / 4;
- int pos = quit % 4;
- // Clear out the old value
- *p &= (255 - QCmasks[pos]);
- // Put in the new value
- *p |= val << QCshifts[pos];
- } // QuadCode::SetQuit
-
- ///////////////////////////////////////////////////////
- // QuadCode::ToIJ: Convert the quadcode value to (I,J).
- // The offsets returned are the coords of the
- // upper-left corner of the quadcode.
-
- void QuadCode::ToIJ (COORD &i, COORD &j, int &nq)
- // i is the row#
- // j is the col#
- // nq is the #quits
- {
- i = j = nq = 0;
- if (nquits < 1)
- return;
- assert (nquits <= MAXQUITS);
- nq = nquits;
-
- // Go from lsq to msq. Following loop is based on the
- // conversion algorithm by Gargantini:
- #ifdef MSB_FIRST
- BYTE *ip = (BYTE *)&i + sizeof(COORD) - 1;
- BYTE *jp = (BYTE *)&j + sizeof(COORD) - 1;
- #else
- BYTE *ip = (BYTE *)&i;
- BYTE *jp = (BYTE *)&j;
- #endif
- int quit, // current quit# in qc
- bit = 0; // current bit# in byte of (i,j)
-
- for (quit = nquits-1; quit >= 0; quit--)
- {
- int val = GetQuit (quit);
- // Bit pos 0 gives J val, bit pos 1 gives I val.
- int ival = val >> 1;
- int jval = val & 1;
- *ip |= (ival << bit);
- *jp |= (jval << bit);
- // Advance to next bit
- if (bit == 7)
- {
- bit = 0;
- #ifdef MSB_FIRST
- ip--;
- jp--;
- #else
- ip++;
- jp++;
- #endif
- }
- else
- bit++;
- } // for quit
-
- } // QuadCode::ToIJ
-
- ///////////////////////////////////////////////////////
- // QuadCode::Compare: Compare one quadcode to another.
- // Return 0 if the two quadcodes are equal; -1 if the
- // current quadcode is less than qc; or +1 if the
- // current quadcode is greater than qc.
-
- int QuadCode::Compare (QuadCode &qc)
- // qc is the quadcode to compare to
- {
- // Check for zero-length quadcodes
- if (nquits == 0)
- {
- if (qc.nquits == 0)
- return 0;
- else
- return -1;
- }
- else if (qc.nquits == 0)
- return 1;
-
- BYTE *p1 = qca;
- BYTE *p2 = qc.qca;
- BYTE *end1 = p1 + QC_NBYTES (nquits) - 1;
- BYTE *end2 = p2 + QC_NBYTES (qc.nquits) - 1;
-
- // Compare each byte of the two quadcodes.
- for ( ; p1 <= end1 && p2 <= end2; p1++, p2++)
- if (*p1 != *p2)
- {
- if (*p1 < *p2)
- return -1;
- else
- return 1;
- }
-
- if (nquits == qc.nquits)
- // quadcodes same
- return 0;
- else if (nquits < qc.nquits)
- // this quadcode contains qc
- return -1;
- else
- // qc contains this quadcode
- return 1;
- } // QuadCode::Compare
-
- ///////////////////////////////////////////////////////
- // QuadCode::Sibling: Compare one quadcode to another.
- // Return TRUE if they are siblings, FALSE if not.
-
- int QuadCode::Sibling (QuadCode *qc)
- // qc is the quadcode to compare to
- {
- // Must be the same length, can't be empty.
- if (qc == NULL || nquits != qc->nquits || nquits==0)
- return (FALSE);
-
- BYTE *p1 = qca;
- BYTE *p2 = qc->qca;
- BYTE *end1 = p1 + QC_NBYTES (nquits) - 1;
-
- // Compare each byte of the two quadcodes.
- // If any differ except the last, then not siblings.
- for ( ; p1 < end1; p1++, p2++)
- if (*p1 != *p2)
- return (FALSE);
-
- if (*p1 == *p2)
- // Quadcodes are same
- return (FALSE);
-
- // Make sure final byte matches in all but last quit.
- int pos = (nquits-1) % 4;
- return
- ((*p1 & QCimasks[pos]) == (*p2 & QCimasks[pos]));
-
- } // QuadCode::Sibling
-
- ///////////////////////////////////////////////////////
- // QuadCode::Contains: Compare one quadcode to another.
- // Return TRUE if the current quadcode contains qc
- // (i.e., is equal to it or is a parent of it), or
- // FALSE otherwise.
-
- int QuadCode::Contains (QuadCode &qc)
- // qc is the quadcode to compare to
- {
- if (nquits > qc.nquits)
- return (FALSE);
- if (nquits == 0)
- return (TRUE);
-
- BYTE *p1 = qca;
- BYTE *p2 = qc.qca;
- BYTE *end1 = p1 + QC_NBYTES (nquits) - 1;
- BYTE *end2 = p2 + QC_NBYTES (qc.nquits) - 1;
-
- // Compare each byte of the two quadcodes.
- for ( ; p1 <= end1 && p2 <= end2; p1++, p2++)
- if (*p1 != *p2)
- {
- // Found a byte that differs. This quadcode
- // contains qc iff: (1) We are at the last byte
- // of this quadcode; and (2) All quits in this
- // quadcode before the last one match the
- // corresponding quits in qc.
- if (p1 != end1)
- return (FALSE);
- int lastpos = (nquits - 1) % 4;
- int pos;
- for (pos = lastpos; pos >= 0; pos--)
- if ((*p1 & QCmasks[pos]) !=
- (*p2 & QCmasks[pos]))
- return (FALSE);
- // They match up to nquits.
- return (TRUE);
- }
-
- // All bytes match - either qc's are same or this is
- // the parent.
- return (TRUE);
- } // QuadCode::Contains
-
- ///////////////////////////////////////////////////////
- // QuadCode::MakeParent: Make quadcode into its parent
-
- void QuadCode::MakeParent (void)
- {
- // Clear the bits that saved the last quit. We do
- // not bother to reclaim storage if the size of the
- // quadcode is reduced.
- nquits--;
- int byte = nquits / 4;
- int pos = nquits % 4;
- *(qca + byte) &= QCimasks[pos];
- } // QuadCode::MakeParent
-
- ///////////////////////////////////////////////////////
- // QuadCode::operator=: Assign one quadcode the same
- // value as another. Note that the target quadcode is
- // assumed to be initialized already.
-
- QuadCode &QuadCode::operator= (QuadCode &qc)
- // qc is the quadcode to copy
- {
- #ifdef STAT_QC
- memcpy (qca, qc.qca, NBYTE_QC);
- #else
- FreeMem();
-
- size_t nbytes = QC_NBYTES (qc.nquits);
- qca = new BYTE [nbytes];
- assert (qca != NULL);
- memcpy (qca, qc.qca, nbytes);
- #endif // STAT_QC
-
- nquits = qc.nquits;
- return (*this);
- } // QuadCode::operator=
-
- ///////////////////////////////////////////////////////
- // operator<<: Overload the "Put to" operator for
- // QuadCode output to stream.
-
- ostream &operator<< (ostream &stream, QuadCode &qc)
- // stream is the stream to print to
- // qc is the quadcode to print
- {
- int quit;
-
- for (quit = 0; quit < qc.nquits; quit++)
- stream << (char)(qc.GetQuit (quit) + '0');
- return (stream);
- } // operator<<
-
- ///////////////////////////////////////////////////////
- // operator>>: Overload the "Get From" operator for
- // QuadCode input from stream.
-
- istream &operator>> (istream &stream, QuadCode &qc)
- // stream is the stream to get from
- // qc is the quadcode to store the result in
- {
- char tmp[80];
-
- qc.FreeMem();
- stream >> tmp;
- qc.Init (tmp);
- return (stream);
- } // operator>>
-